package com.moss.cloud.common.security.annotation.aspect;

import com.alibaba.fastjson2.JSONObject;
import com.moss.cloud.common.core.constant.MsgTopic;
import com.moss.cloud.common.core.model.dto.MessageDTO;
import com.moss.cloud.common.core.model.dto.OperationLogDTO;
import com.moss.cloud.common.core.utils.DateUtil;
import com.moss.cloud.common.core.utils.UserContextHolder;
import com.moss.cloud.common.security.component.MessageEventSender;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.moss.cloud.common.security.annotation.SysLog;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;

import com.moss.cloud.common.core.utils.IpUtil;
import com.moss.cloud.common.core.enums.MsgTypeEnum;
import com.moss.cloud.common.core.enums.MsgActionEnum;

/**
 * 微服务系统操作日志切面实现
 *
 * @author 瑾年
 * @data 2023年3月14日
 */
@Component
@Aspect
@Slf4j
public class SysLogAspectImpl {
    @Resource
    MessageEventSender messageEventSender;

    /**
     * 环绕通知
     *
     * @author 瑾年
     * @data 2020/05/05
     */
    @Around("@annotation(sysLog)")
    public Object around(ProceedingJoinPoint point, SysLog sysLog) throws Throwable {
        try {
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            Object[] args = point.getArgs();//参数
            Signature signature = point.getSignature();
            MethodSignature methodSignature = (MethodSignature) signature;
            //2.最关键的一步:通过这获取到方法的所有参数名称的字符串数组
            String[] parameterNames = methodSignature.getParameterNames();
            String classType = point.getTarget().getClass().getName();
            Class<?> clazz = Class.forName(classType);
            String clazzName = clazz.getName();
            String methodName = point.getSignature().getName(); //获取方法名称
            String userName = "";
            Long tenantId = UserContextHolder.getTenantId();
            String ipAddr = IpUtil.getIpAddr(request);
            if (StringUtils.isNotBlank(UserContextHolder.getUsername())) {
                userName = UserContextHolder.getUsername();
            }
            OperationLogDTO dto = new OperationLogDTO();
            if(!methodSignature.getReturnType().equals(void.class)){
                dto.setArgs(JSONObject.toJSONString(args));
                dto.setArgsName(JSONObject.toJSONString(parameterNames));
            }
            dto.setClazzName(clazzName);
            dto.setCreatDate(DateUtil.localDateTimeToString(LocalDateTime.now()));
            dto.setIpAddr(ipAddr);
            dto.setMethodName(methodName);
            dto.setOperation(sysLog.operation());
            dto.setServerName(sysLog.serverName());
            dto.setUserName(userName);
            dto.setTenantId(tenantId);
            this.buildOperationLog(dto);
        } catch (ClassNotFoundException e) {
            log.info("异常信息:{}", e.getMessage());
        }
        return point.proceed();
    }

    /**
     * 构建日志消息对象
     */
    private void buildOperationLog(OperationLogDTO dto) {
        MessageDTO messageDTO = new MessageDTO(MsgTypeEnum.ONE.name(), MsgActionEnum.ADD.name(), dto);
        messageEventSender.sendMessage(MsgTopic.SYSTEM_LOG_MESSAGE,
                messageDTO);
    }
}
